﻿using Chart3D;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using PGMHelper;

namespace WSAP
{
    /// <summary>
    /// WElementNet拓展方法
    /// </summary>
    public static class WElementNetExtension
    {
        #region 绘图相关

        /// <summary>
        /// 获得单元绘图数据
        /// </summary>
        /// <param name="element"></param>
        /// <param name="isDeform"></param>
        /// <returns></returns>
        public static DataSeries GetData(this WElementNet element, double factor)
        {
            //获得节点列表
            var nodes = element.GetNodes();
            //节点数少于二直接返回
            if (nodes.Count < 2) return null;
            //判断构件类型
            if (nodes.Count == 2) return element.GetFrameData(factor);
            //壳单元
            else if (nodes.Count == 4) return element.GetShellData(true, factor);
            else return null;
        }

        /// <summary>
        /// 获得单元绘图数据
        /// </summary>
        /// <param name="element"></param>
        /// <param name="isDeform"></param>
        /// <returns></returns>
        public static DataSeries GetData(this WElementNet element, int modeID, double factor)
        {
            //获得节点列表
            var nodes = element.GetNodes();
            //节点数少于二直接返回
            if (nodes.Count < 2) return null;
            //数据点
            var prtI = nodes[0].GetPoint3D(modeID, factor);
            var prtJ = nodes[1].GetPoint3D(modeID, factor);
            //判断构件类型
            if (nodes.Count == 2) return element.GetFrameData(prtI, prtJ);
            //壳单元
            else if (nodes.Count == 4)
            {
                var prtK = nodes[2].GetPoint3D(modeID, factor);
                var prtL = nodes[3].GetPoint3D(modeID, factor);
                return element.GetShellData(prtI, prtJ, prtK, prtL);
            }
            else return null;
        }

        /// <summary>
        /// 获得单元绘图数据
        /// </summary>
        /// <param name="element"></param>
        /// <param name="prtI"></param>
        /// <param name="prtJ"></param>
        /// <param name="isDeform"></param>
        /// <param name="color"></param>
        /// <param name="thick"></param>
        /// <param name="factor"></param>
        /// <returns></returns>
        private static DataSeries GetFrameData(this WElementNet element, Point3D prtI, Point3D prtJ, 
            Color color, float thick, double factor, bool includeInterpolation)
        {
            //构造曲线
            var data = new DataSeries(DrawType.Line, false);
            //添加数据点
            data.AddPoint(prtI);
            //判断是否加入中间点
            if (includeInterpolation) element.SetInterpolationPoints(data, StructrueChart.FrameInterpolationPrtNum, factor);
            data.AddPoint(prtJ);
            //设定颜色
            if(color == Color.White)
                data.SetLineStyle(color, SeriesStyle.PlotLinesMethodEnum.Lines, System.Drawing.Drawing2D.DashStyle.Dash, thick: thick);
            else data.SetLineStyle(color, SeriesStyle.PlotLinesMethodEnum.Splines, thick: thick);
            //返回曲线
            return data;
        }

        /// <summary>
        /// 获得单元绘图数据 普通动态图
        /// </summary>
        /// <param name="element"></param>
        /// <param name="isDeform"></param>
        /// <returns></returns>
        private static DataSeries GetFrameData(this WElementNet element, double factor)
        {
            //获得节点列表
            var nodes = element.GetNodes();
            //数据点
            var prtI = nodes[0].GetPoint3D(factor != 1, factor);
            var prtJ = nodes[1].GetPoint3D(factor != 1, factor);
            //如果未放大则按黑白线绘制
            if(factor == 1)
                return element.GetFrameData(prtI, prtJ, Color.White, 1F, factor, false);
            //变形后状态
            if (Math.Abs(nodes[0].GetZ() - nodes[1].GetZ()) < 100)
                return element.GetFrameData(prtI, prtJ, Color.Yellow, 2F, factor, true);
            else return element.GetFrameData(prtI, prtJ, Color.Green, 10F, factor, true);
        }

        /// <summary>
        /// 获得单元绘图数据 模态分析为主
        /// </summary>
        /// <param name="element"></param>
        /// <param name="isDeform"></param>
        /// <returns></returns>
        private static DataSeries GetFrameData(this WElementNet element, Point3D prtI, Point3D prtJ)
        {
            //获得节点列表
            var nodes = element.GetNodes();
            if (Math.Abs(nodes[0].GetZ() - nodes[1].GetZ()) < 100)
                return element.GetFrameData(prtI, prtJ, Color.Yellow, 2F, 1F, false);
            else return element.GetFrameData(prtI, prtJ, Color.Green, 10F, 1F, false);
        }

        /// <summary>
        /// 获得单元绘图数据
        /// </summary>
        /// <param name="element"></param>
        /// <param name="prtI"></param>
        /// <param name="prtJ"></param>
        /// <param name="prtK"></param>
        /// <param name="prtL"></param>
        /// <returns></returns>
        private static DataSeries GetShellData(this WElementNet element, Point3D prtI, Point3D prtJ, Point3D prtK, Point3D prtL)
        {
            //构造曲线
            var data = new DataSeries(DrawType.Surface, false);
            data.PointArray = new Point3D[2, 2];
            data.PointArray[0, 0] = prtI; data.PointArray[0, 1] = prtJ;
            data.PointArray[1, 0] = prtL; data.PointArray[1, 1] = prtK;
            data.AddPoint(prtI); data.AddPoint(prtJ);
            data.AddPoint(prtK); data.AddPoint(prtL);
            //设定线形
            data.SetLineStyle(Color.LightGray, SeriesStyle.PlotLinesMethodEnum.Lines);
            return data;
        }

        /// <summary>
        /// 获得单元绘图数据
        /// </summary>
        /// <param name="element"></param>
        /// <param name="isDeform"></param>
        /// <returns></returns>
        private static DataSeries GetShellData(this WElementNet element, bool isDeform, double factor)
        {
            //获得节点列表
            var nodes = element.GetNodes();
            //数据点
            var prtI = nodes[0].GetPoint3D(isDeform, factor);
            var prtJ = nodes[1].GetPoint3D(isDeform, factor);
            var prtK = nodes[2].GetPoint3D(isDeform, factor);
            var prtL = nodes[3].GetPoint3D(isDeform, factor);
            //返回数据
            return element.GetShellData(prtI, prtJ, prtK, prtL);
        }

        #endregion

        /// <summary>
        /// 三次样条插值获得中间点
        /// </summary>
        /// <param name="element"></param>
        /// <param name="prtNum"></param>
        /// <returns></returns>
        private static void SetInterpolationPoints(this WElementNet element, DataSeries data, int prtNum, double factor)
        { 
            //获得节点列表
            var nodes = element.GetNodes();
            //遍历
            for(int prtIndex = 1; prtIndex <= prtNum; prtIndex++)
            {
                //求得Factor
                var lengthFactor = prtIndex / (prtNum + 1.0);
                //获得数据点
                data.AddPoint(nodes[0].GetPoint3D(nodes[1], lengthFactor, factor));
            }
        }

        /// <summary>
        /// 获得响应最大的节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="responseType"> 响应类型 </param>
        /// <returns></returns>
        public static WNodeNet GetMaxResponseNode(this WElementNet element, WNodeNet targetNode, NodeResponseEnum responseType, int dof)
        {
            //遍历单元
            element.GetNodes().ForEach(node => targetNode = targetNode.GetMaxResponseNode(node, responseType, dof));
            return targetNode;
        }

        /// <summary>
        /// 获得响应最大的节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="responseType"> 响应类型 </param>
        /// <returns></returns>
        public static WNodeNet GetMaxResponseNode(this WElementNet element, WNodeNet targetNode, NodeResponseEnum responseType, int dof, double z)
        {
            //遍历单元
            element.GetNodes().ForEach(node =>
            {
                if (Math.Abs(node.GetZ() - z) < 5)
                {
                    targetNode = targetNode.GetMaxResponseNode(node, responseType, dof);
                }
            });
            return targetNode;
        }

        /// <summary>
        ///  获得振型向量最大值
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static double GetMaxAbsEigenVertorValue(this WElementNet element, int modeID)
        {
            var valueList = (from node in element.GetNodes() select node.GetMaxAbsEigenVertorValue(modeID)).ToList();
            return valueList.Max();
        }

        /// <summary>
        /// 获得模型最大尺度
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static Tuple<List<double>, List<double>, List<double>> GetPosList(this WElementNet element)
        {
            //获得节点列表
            var nodes = element.GetNodes();
            return Tuple.Create<List<double>, List<double>, List<double>>(
                (from node in nodes select node.GetX()).ToList(),
                  (from node in nodes select node.GetY()).ToList(),
                    (from node in nodes select node.GetZ()).ToList()
                );
        }

        /// <summary>
        /// 设定弹性框架单元属性
        /// </summary>
        /// <param name="E"> 弹性模量 </param>
        /// <param name="G"> 剪切模量 </param>
        /// <param name="A"> 截面面积 </param>
        /// <param name="Ip"> 扭转惯量 </param>
        /// <param name="Iy"> 绕截面y轴转动惯量 </param>
        /// <param name="Iz"> 绕截面z轴转动惯量 </param>
        /// <param name="avy"> 剪切面积 </param>
        /// <param name="avz"> 剪切面积 </param>
        /// <returns></returns>
        public static bool SetElasticFrameElementProperties(this WElementNet element, double E, double G, 
            double A, 
            double Ip, double Iy, double Iz)
        {
            return element.SetProperties(new List<double> { E, G, A, Ip, Iy, Iz });
        }

        /// <summary>
        /// 设定弹性壳单元属性
        /// </summary>
        /// <param name="thickness"> 厚度 </param>
        /// <param name="E"> 弹性模量 </param>
        /// <param name="possionFactor"> 泊松比 </param>
        /// <returns></returns>
        public static bool SetElasticShellProperties(this WElementNet element, double thickness, double E, double possionFactor)
        {
            return element.SetProperties(new List<double> { thickness, E, possionFactor });
        }

        /// <summary>
        /// 设定单元端部释放
        /// </summary>
        /// <param name="element"></param>
        /// <param name="releaseType"></param>
        /// <returns></returns>
        public static bool SetReleaseType(this WElementNet element, FrameReleaseEnum releaseType)
        {
            return element.SetReleaseType((int)releaseType);
        }

        /// <summary>
        /// 获得单元力
        /// </summary>
        /// <param name="element"></param>
        /// <param name="forceType"></param>
        /// <returns></returns>
        public static List<double> GetSectionForces(this WElementNet element, FrameLocalForceEnum forceType)
        {
            return element.GetSectionForceList((int)forceType);
        }

        #region 截面力曲线及数据

        /// <summary>
        /// 获得绘图数据
        /// </summary>
        /// <param name="element"></param>
        /// <param name="forceType"></param>
        /// <returns></returns>
        public static GridViewDatas GetData(this WElementNet element, FrameLocalForceEnum forceType)
        {
            //初始化
            var data = new GridViewDatas();
            //获得截面位置
            var sectionPos = element.GetSectionPosList();
            sectionPos.Insert(0, 0);
            //增加列
            data.Add(new GridViewColumn(sectionPos, 3, titleName: "截面位置", width: 80));
            data.Add(new GridViewColumn(element.GetSectionForces(forceType), 2, 
                titleName: "截面力", width: 120));
            //返回数据
            return data;
        }

        /// <summary>
        /// 绘制内力曲线
        /// </summary>
        /// <param name="element"></param>
        public static void SectionForceToChart(this WElementNet element)
        {
            var f = new ElementForceForm(element);
            f.Show();
        }

        /// <summary>
        /// 截面力绘图
        /// </summary>
        /// <param name="element"></param>
        /// <param name="forceType"></param>
        public static void SectionForceToChart(this WElementNet element, System.Windows.Forms.DataVisualization.Charting.Chart chart, FrameLocalForceEnum forceType)
        {
            //序列名称
            var titileName = string.Format("单元{0}_{1}", element.GetTag(), forceType.ToString());
            //增加序列
            chart.AddSeries(titileName, System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line);
            //获得截面位置
            var sectionPos = element.GetSectionPosList();
            sectionPos.Insert(0, 0);
            //绘图
            chart.Series[titileName].Points.DataBindXY(sectionPos, element.GetSectionForces(forceType));
        }

        #endregion
    }
}
